#include <iostream>
#include <cstring>
#include <string>

#include <boost/thread/thread.hpp>
#include <boost/lambda/lambda.hpp>

#include <sndfile.h>
#include "portaudio.h"


using namespace std;

class AudioObj{
    private:
        SF_INFO sfi;
        SNDFILE *sf;
        sf_count_t nread;
        size_t nframes;
        float *buf;
        sf_count_t playpos;
        bool F_pause;
    public:
        AudioObj(string fileName){
            F_pause = false;
            nframes = 512;
            playpos = 0;
            memset(&sfi, 0, sizeof(sfi));
            if ((sf = sf_open(fileName.c_str(), SFM_READ, &sfi)) == NULL){
                cout << "Could not open " << fileName << "." << endl;
            }
            buf = new float[nframes * sfi.channels];
        }
        ~AudioObj(){
            sf_close(sf);
            delete buf;
        }
        void setPos(sf_count_t pos){
            playpos = pos;
        }
        sf_count_t getPos(){
            return playpos;
        }
        void pause(){
            F_pause = true;
        }
        void stop(){
            F_pause = true;
            sf_count_t p = 0;
            setPos(p);
        }
        sf_count_t play(PaStream *stream){
            F_pause = false;
            Pa_OpenDefaultStream(&stream, 
                    0, 
                    sfi.channels, 
                    paFloat32, 
                    sfi.samplerate, 
                    paFramesPerBufferUnspecified, 
                    NULL, 
                    NULL);
            Pa_StartStream(stream);

            sf_seek(sf, playpos, SEEK_SET);
            while ((nread = sf_readf_float(sf, buf, nframes)) > 0){
                Pa_WriteStream(stream, buf, nread);
                playpos += nread;
                if (F_pause)
                    break;
            }
            Pa_StopStream(stream);
            Pa_CloseStream(stream);
            return playpos;
        }
};

class AudioPlayer{
    private:
        boost::thread* playthrd;
        AudioObj *audio;
        sf_count_t playpos;
        bool isPlaying;
        bool inited;
    public:
        AudioPlayer(){
            // audio = x;
            // playpos = 0;
            isPlaying = false;
            inited = false;
        }
        ~AudioPlayer(){
            if (inited)
                delete audio;
        }

        void openfile(string filename){
            audio = new AudioObj(filename);
            inited = true;
        }
        void stop(){
            audio->stop();
            isPlaying=false;
        }
        void play(PaStream *stream){
            if (isPlaying) 
                return;
            playthrd = new boost::thread(boost::bind(&AudioObj::play, audio, stream));
            // playthrd = new boost::thread(boost::lambda::var(playpos) = audio->play(stream, playpos));
            isPlaying = true;
            // playthrd->join();
            //todo
        }
        void pause(){
            // cout << "Now in audioPlayer's pause function" << endl;
            audio->pause();
            isPlaying = false;
        }
};




int main(int argc, char **argv)
{
    if (argc < 2){
        cout << "Syntax: " << argv[0] << " <filename>" << endl;
        return 1;
    }
    string Fname(argv[1]);
//    AudioObj audio(Fname);
    PaStream *stream;
    Pa_Initialize();

    AudioPlayer player;
    player.openfile(Fname);
    player.play(stream);

    string ctrl;
    cout << "pause/play/stop/exit" << endl;
    while (cin >> ctrl){
        if (ctrl.compare("pause")==0)
            player.pause();
        if (ctrl.compare("play")==0)
            player.play(stream);
        if (ctrl.compare("stop")==0)
            player.stop();
        if (ctrl.compare("exit")==0)
            break;
    }
    Pa_Terminate();
    return 0;
}





